﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.CodeDom;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.IO;

namespace NRemedy
{
    public class CSharpClassGenerator
    {
        private ARLogInRequestContext _context;
        private IARServer _server;
        private CodeGeneratorOptions _options;

        public CSharpClassGenerator(ARLogInRequestContext context)
        {
            if (context == null) throw new ArgumentNullException("context");
            _context = context;
            _server = ARServerFactory.CreateARServer();

            //            
            _options = new CodeGeneratorOptions();
            _options.BlankLinesBetweenMembers = false;
            _options.IndentString = "\t";
        }

        public IEnumerable<BMC.ARSystem.ARForm> GetListForm(ARFormFilterDelegate formFilter)
        {
            //_server.LogIn(_context);

            var result =  _server.GetListForm(formFilter);

            //_server.LogOut();

            return result;
        }

        public IEnumerable<BMC.ARSystem.Field> GetListField(string formName, ARFieldFilterDelegate fieldFilter)
        {
            //_server.LogIn(_context);

            var result = _server.GetListField(formName, fieldFilter);

            //_server.LogOut();

            return result;
        }

        #region defined form filter

        public static bool FormFilterBase(BMC.ARSystem.ARForm form)
        {
            if (form == null) return false;
            return true;
        }

        public static bool FormFilterIsDisplayOnlyForm(BMC.ARSystem.ARForm form)
        {
            if (form is BMC.ARSystem.DisplayOnlyForm) return true;
            return false;
        }

        public static bool FormFilterIsRegularForm(BMC.ARSystem.ARForm form)
        {
            if (form is BMC.ARSystem.RegularForm) return true;
            return false;
        }

        public static bool FormFilterIsJoinForm(BMC.ARSystem.ARForm form)
        {
            if (form is BMC.ARSystem.JoinForm) return true;
            return false;
        }

        public static bool FormFilterIsVendorForm(BMC.ARSystem.ARForm form)
        {
            if (form is BMC.ARSystem.VendorForm) return true;
            return false;
        }

        public static bool FormFilterIsViewForm(BMC.ARSystem.ARForm form)
        {
            if (form is BMC.ARSystem.ViewForm) return true;
            return false;
        }

        public static bool FormFilterWithRegex(BMC.ARSystem.ARForm form,string pattern)
        {
            if (string.IsNullOrEmpty(pattern)) return true;
            if (Regex.Match(form.Name, pattern,RegexOptions.IgnoreCase).Value == form.Name) return true;
            return false;
        }

        #endregion

        #region defined field filter

        public static bool FieldFilterBase(BMC.ARSystem.Field field)
        {
            if (field == null) return false;
            return true;
        }

        public static bool FieldFilterIsDataField(BMC.ARSystem.Field field)
        {
            return field.IsDataField();
        }

        public static bool FieldFilterIsIntegerField(BMC.ARSystem.Field field)
        {
            return field.DataType == 2u;
        }

        public static bool FieldFilterIsRealField(BMC.ARSystem.Field field)
        {
            return field.DataType == 3u;
        }

        public static bool FieldFilterIsCharacterField(BMC.ARSystem.Field field)
        {
            return field.DataType == 4u;
        }

        public static bool FieldFilterIsDiaryField(BMC.ARSystem.Field field)
        {
            return field.DataType == 5u;
        }

        public static bool FieldFilterIsSelectionField(BMC.ARSystem.Field field)
        {
            return field.DataType == 6u || field.DataType == 8u;
        }

        public static bool FieldFilterIsDateTimeField(BMC.ARSystem.Field field)
        {
            return field.DataType == 7u;
        }

        public static bool FieldFilterIsDecimalField(BMC.ARSystem.Field field)
        {
            return field.DataType == 10u;
        }

        public static bool FieldFilterIsAttachmentField(BMC.ARSystem.Field field)
        {
            return field.DataType == 11u;
        }

        public static bool FieldFilterIsCurrencyField(BMC.ARSystem.Field field)
        {
            return field.DataType == 12u;
        }

        public static bool FieldFilterIsDateOnlyField(BMC.ARSystem.Field field)
        {
            return field.DataType == 13u;
        }

        public static bool FieldFilterIsTimeOnlyField(BMC.ARSystem.Field field)
        {
            return field.DataType == 14u;
        }

        public static bool FieldFilterIsReservedField(BMC.ARSystem.Field field)
        {
            return field.IsCoreField;
        }

        #endregion


        public string GenerateClassByFormName(string FormName)
        {
            CodeCompileUnit ccu = new CodeCompileUnit();
            //root namespace
            GenerateRootNamespace rn = new GenerateRootNamespace();
            rn.Create(ccu);
            //import namespace
            GenerateImportNamespace imn = new GenerateImportNamespace();
            imn.Create(ccu.Namespaces[0]);
            //class
            GenerateClass gc = new GenerateClass();
            gc.Create(ccu.Namespaces[0], DefaultClassNameResolver(FormName), FormName);

            _server.LogIn(_context);
            var fields = GetListField(FormName, delegate(BMC.ARSystem.Field field) {
                return CSharpClassGenerator.FieldFilterIsDataField(field) && !CSharpClassGenerator.FieldFilterIsReservedField(field);
            });
            GenerateField gf = new GenerateField();
            
            foreach (var f1 in fields){
                gf.Create(ccu.Namespaces[0].Types[0], DefaultFieldNameResolver(f1.Name), ARDataTypeConvert.MappingARType(f1.DataType));
            }

            GenerateProperty gp = new GenerateProperty();
            Dictionary<string, object> mapping = new Dictionary<string, object>();
            foreach (var f2 in fields){
                mapping.Clear();
                mapping.Add("DatabaseID", f2.Id);
                mapping.Add("DatabaseName", f2.Name);
                mapping.Add("DataType", (ARType)f2.DataType);
                gp.Create(ccu.Namespaces[0].Types[0], DefaultPropertyNameResolver(f2.Name), ARDataTypeConvert.MappingARType(f2.DataType), mapping);
            }
            _server.LogOut();
            return GenerateCodeByCodeCompileUnit(ccu);
        }

        private string GenerateCodeByCodeCompileUnit(CodeCompileUnit ccu)
        {
            CSharpCodeProvider provider = new CSharpCodeProvider();
            StringWriter sw = new StringWriter();
            string code = string.Empty;
            try
            {
                provider.GenerateCodeFromCompileUnit(ccu, sw, _options);
                sw.Flush();
                code = sw.GetStringBuilder().ToString();
                return code;
            }
            catch(Exception ex) {
                throw ex;
            }
            finally
            {
                sw.Close();
            }
        }

        public virtual string DefaultClassNameResolver(string formName)
        {
            return Regex.Replace(formName,@"[^\w]+","");
        }

        public virtual string DefaultFieldNameResolver(string fieldName)
        {
            return "_" + Regex.Replace(fieldName, @"[^\w]+", "");
        }

        public virtual string DefaultPropertyNameResolver(string fieldName)
        {
            return Regex.Replace(fieldName, @"[^\w]+", "");
        }

    }
}
